import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { IS_PUBLIC_KEY } from '@/decorators/public.decorator';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { UserService } from '@/modules/user/user.service';
import { ROLES_KEY } from '@/decorators/role.decorator';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private jwtService: JwtService,
    private configService: ConfigService,
    private userService: UserService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 公共接口可以不校验权限
    const isPublic: boolean = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic) {
      return true;
    }
    // 校验token
    const request = context.switchToHttp().getRequest();
    const token = extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException('没有token');
    }
    // 校验接口权限
    if (request.user) {
    } else {
      try {
        const payload = await this.jwtService.verifyAsync(token, {
          secret: this.configService.get<string>('JWT_SECRET'),
        });
        if (payload && (payload.userid || payload.userId)) {
          const userId = payload.userid || payload.userId;
          // 查询数据库中是否有这个用户
          const user = await this.userService.findOne(userId);
          if (!user) {
            return false;
          }

          // 校验接口权限
          const roles: number[] = this.reflector.getAllAndOverride(ROLES_KEY, [
            context.getHandler(),
            context.getClass(),
          ]);
          if (roles) {
            let hasRole = false
            const roleIds = []
            for (let i = 0; i < user.roles.length; i++) {
              roleIds.push(user.roles[i].id);
            }
            for (const role of roles) {
              if (roleIds.includes(role)) {
                hasRole = true
              }
            }
            if (!hasRole) {
              return false;
            }
          }
        }
        request.user = payload;

        return true;
      } catch (e) {
        throw new UnauthorizedException('token失效');
      }
    }
    return false;
  }
}

function extractTokenFromHeader(request) {
  const { authorization } = request.headers;
  if (authorization) {
    const data = authorization.split(' ');
    if (data[0] === 'Bearer') {
      return data[1];
    }
  }
  return '';
}
